热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基点|精力_Go基础加密算法和数据结构

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Go基础加密算法和数据结构相关的知识,希望对你有一定的参考价值。文章目录

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Go基础加密算法和数据结构相关的知识,希望对你有一定的参考价值。



文章目录


  • 一、加密算法
    • 1. 对称加密
    • 2. 非对称加密
    • 3. 哈希算法

  • 二、数据结构与算法
    • 1. 链表
    • 2. 栈
    • 3. 堆
    • 4. Trie树



一、加密算法

1. 对称加密

加密过程的每一步都是可逆的
加密和解密用的是同一组密钥
异或是最简单的对称加密算法

// XOR 异或运算,要求plain和key的长度相同
func XOR(plain string, key []byte) string
bPlain := []byte(plain)
bCipher := make([]byte, len(key))
for i, k := range key
bCipher[i] = k ^ bPlain[i]

cipher := string(bCipher)
return cipher

DES(Data Encryption Standard)数据加密标准,是目前最为流行的加密算法之一
对原始数据(明文)进行分组,每组64位,最后一组不足64位时按一定规则填充,每一组上单独施加DES算法
DES子密钥生成
初始密钥64位,实际有效位56位,每隔7位有一个校验位,根据初始密钥生成16个48位的子密钥

N取值从1到16,N和x有固定的映射表

DES加密过程

L1, R1 = f(L0, R0, K1),依此循环,得到L16和R16
S盒替换,输入48位,输出32位,各分为8组,输入每组6位,输出每组4位,分别在每组上施加S盒替换,一共8个S盒

CBC加密过程

分组模式,CBC(Cipher Block Chaining )密文分组链接模式,将当前明文分组与前一个密文分组进行异或运算,然后再进行加密
其他分组模式还有ECB, CTR, CFR, OFB

func DesEncryptCBC(text string, key []byte) (string, error)
src := []byte(text)
block, err := des.NewCipher(key) // 用des创建一个加密器cipher
if err != nil
return "", err

blockSize := block.BlockSize() // 分组的大小,blockSize=8
src = common.ZeroPadding(src, blockSize) // 填充
out := make([]byte, len(src)) // 密文和明文的长度一致
encrypter := cipher.NewCBCEncrypter(block, key) // CBC分组模式加密
encrypter.CryptBlocks(out, src)
return hex.EncodeToString(out), nil

func DesDecryptCBC(text string, key []byte) (string, error)
src, err := hex.DecodeString(text) // 转成[]byte
if err != nil
return "", err

block, err := des.NewCipher(key)
if err != nil
return "", err


out := make([]byte, len(src)) // 密文和明文的长度一致
encrypter := cipher.NewCBCDecrypter(block, key) // CBC分组模式解密
encrypter.CryptBlocks(out, src)
out = common.ZeroUnPadding(out) // 反填充
return string(out), nil

AES(Advanced Encryption Standard)高级加密标准,旨在取代DES


2. 非对称加密


  • 使用公钥加密,使用私钥解密
  • 公钥和私钥不同
  • 公钥可以公布给所有人
  • 私钥只有自己保存
  • 相比于对称加密,运算速度非常慢

对称加密和非对称加密结合使用的案例:
小明要给小红传输机密文件,他俩先交换各自的公钥,然后:


  • 小明生成一个随机的AES口令,然后用小红的公钥通过RSA加密这个口令,并发给小红
  • 小红用自己的RSA私钥解密得到AES口令
  • 双方使用这个共享的AES口令用AES加密通信

RSA是三个发明人名字的缩写:Ron Rivest,Adi Shamir,Leonard Adleman,密钥越长,越难破解,目前768位的密钥还无法破解(至少没人公开宣布),因此可以认为1024位的RSA密钥基本安全,2048位的密钥极其安全,RSA的算法原理主要用到了数论
RSA加密过程:


  • 随机选择两个不相等的质数p和q:p=61, q=53
  • 计算p和q的乘积n:n=3233
  • 计算n的欧拉函数φ(n) = (p-1)(q-1): φ(n) =3120
  • 随机选择一个整数e,使得1
  • 计算e对于φ(n)的模反元素d,即求解e*d+ φ(n)*y=1:d=2753, y=-15
  • 将n和e封装成公钥,n和d封装成私钥:公钥=(3233,17),公钥=(3233,2753)

// RSA加密
func RsaEncrypt(origData []byte) ([]byte, error)
// 解密pem格式的公钥
block, _ := pem.Decode(publicKey)
if block == nil
return nil, errors.New("public key error")

// 解析公钥
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) // 目前的数字证书一般都是基于ITU(国际电信联盟)制定的X.509标准
if err != nil
return nil, err

// 类型断言
pub := pubInterface.(*rsa.PublicKey)
// 加密
return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)

// RSA解密
func RsaDecrypt(ciphertext []byte) ([]byte, error)
// 解密
block, _ := pem.Decode(privateKey)
if block == nil
return nil, errors.New("private key error!")

// 解析PKCS1格式的私钥
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil
return nil, err

// 解密
return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)

ECC(Elliptic Curve Cryptography)椭圆曲线加密算法,相比RSA,ECC可以使用更短的密钥,来实现与RSA相当或更高的安全
定义了椭圆曲线上的加法和二倍运算,椭圆曲线依赖的数学难题是:k为正整数,P是椭圆曲线上的点(称为基点), k*P=Q , 已知Q和P,很难计算出k

func genPrivateKey() (*ecies.PrivateKey, error)
pubkeyCurve := elliptic.P256() // 初始化椭圆曲线
// 随机挑选基点,生成私钥
p, err := ecdsa.GenerateKey(pubkeyCurve, rand.Reader) // 用golang标准库生成公私钥对
if err != nil
return nil, err
else
return ecies.ImportECDSA(p), nil // 转换成以太坊的公私钥对


// ECCEncrypt 椭圆曲线加密
func ECCEncrypt(plain string, pubKey *ecies.PublicKey) ([]byte, error)
src := []byte(plain)
return ecies.Encrypt(rand.Reader, pubKey, src, nil, nil)

// ECCDecrypt 椭圆曲线解密
func ECCDecrypt(cipher []byte, prvKey *ecies.PrivateKey) (string, error)
if src, err := prvKey.Decrypt(cipher, nil, nil); err != nil
return "", err
else
return string(src), nil



3. 哈希算法

哈希函数的基本特征:


  • 输入可以是任意长度
  • 输出是固定长度
  • 根据输入很容易计算出输出
  • 根据输出很难计算出输入(几乎不可能)
  • 两个不同的输入几乎不可能得到相同的输出

SHA(Secure Hash Algorithm) 安全散列算法,是一系列密码散列函数,有多个不同安全等级的版本:SHA-1,SHA-224,SHA-256,SHA-384,SHA-512,其作用是防伪装,防窜扰,保证信息的合法性和完整性
sha-1算法大致过程:


  • 填充,使得数据长度对512求余的结果为448
  • 在信息摘要后面附加64bit,表示原始信息摘要的长度
  • 初始化h0到h4,每个h都是32位
  • h0到h4历经80轮复杂的变换
  • 把h0到h4拼接起来,构成160位,返回

func Sha1(data string) string
sha1 := sha1.New()
sha1.Write([]byte(data))
return hex.EncodeToString(sha1.Sum(nil))

MD5(Message-Digest Algorithm 5)信息-摘要算法5,算法流程跟SHA-1大体相似,MD5的输出是128位,比SHA-1短了32位,MD5相对易受密码分析的攻击,但运算速度比SHA-1快

func Md5(data string) string
md5 := md5.New()
md5.Write([]byte(data))
return hex.EncodeToString(md5.Sum(nil))

哈希函数的应用场景


  • 用户密码的存储
  • 文件上传/下载完整性校验
  • mysql大字段的快速对比

数字签名


比特币中验证交易记录的真实性用的就是数字签名,先hash再用私钥加密的原因是:非对称加密计算量比较大,先hash可以把原始数据转一条很短的信息,提高计算效率


二、数据结构与算法

1. 链表

链表的一个应用案例,LRU(Least Recently Used,最近最少使用)缓存淘汰的总体思路:缓存的key放到链表中,头部的元素表示最近刚使用


  • 如果命中缓存,从链表中找到对应的key,移到链表头部
  • 如果没命中缓存:
    • 如果缓存容量没超,放入缓存,并把key放到链表头部
    • 如果超出缓存容量,删除链表尾部元素,再把key放到链表头部

ring的应用:基于滑动窗口的统计,比如最近100次接口调用的平均耗时、最近10笔订单的平均值、最近30个交易日股票的最高点;ring的容量即为滑动窗口的大小,把待观察变量按时间顺序不停地写入ring即可

package main
import (
"container/ring"
"fmt"
)
func TraverseRing(ring *ring.Ring)
// 通过Do()来遍历ring,内部实际上调用了Next()而非Prev()
ring.Do(func(i interface)
fmt.Printf("%v ", i)
)
fmt.Println()

func main()
ring := ring.New(5) // 必须指定长度,各元素被初始化为nil
ring2 := ring.Prev()
for i :&#61; 0; i < 3; i&#43;&#43;
ring.Value &#61; i
ring &#61; ring.Next()

for i :&#61; 0; i < 3; i&#43;&#43;
ring2.Value &#61; i
ring2 &#61; ring2.Prev()

TraverseRing(ring)
TraverseRing(ring2) // ring和ring2当前所在的指针位置不同&#xff0c;所以遍历出来的顺序也不同


2. 栈

栈是一种先进后出的数据结构&#xff0c;push把元素压入栈底&#xff0c;pop弹出栈顶的元素&#xff0c;编程语言的编译系统也用到了栈的思想

go自带的List已经包含了栈的功能&#xff0c;这里实现一个线程安全的栈

type (
node struct
value interface
prev *node

MyStack struct
top *node
length int
lock *sync.RWMutex

)
func NewMyStack() *MyStack
return &MyStacknil, 0, &sync.RWMutex

func (stack *MyStack) Push(value interface)
stack.lock.Lock()
defer stack.lock.Unlock()
n :&#61; &nodevalue, stack.top
stack.top &#61; n
stack.length&#43;&#43;

func (stack *MyStack) Pop() interface
stack.lock.Lock()
defer stack.lock.Unlock()
if stack.length &#61;&#61; 0
return nil

n :&#61; stack.top
stack.top &#61; n.prev
stack.length--
return n.value

func (stack *MyStack) Peak() interface
stack.lock.RLock()
defer stack.lock.RUnlock()
if stack.length &#61;&#61; 0
return nil

return stack.top.value

func (stack *MyStack) Len() int
return stack.length

func (stack *MyStack) Empty() bool
return stack.Len() &#61;&#61; 0


3. 堆

堆是一棵二叉树&#xff0c;大根堆即任意节点的值都大于等于其子节点&#xff0c;反之为小根堆
用数组来表示堆&#xff0c;下标为 i 的结点的父结点下标为(i-1)/2&#xff0c;其左右子结点分别为 (2i &#43; 1)、(2i &#43; 2)

构建堆

package main
import "fmt"
// AdjustTraingle 如果只是修改slice里的元素&#xff0c;不需要传slice的指针&#xff1b;如果要往slice里append或让slice指向新的子切片&#xff0c;则需要传slice指针
func AdjustTraingle(arr []int, parent int)
left :&#61; 2 * parent &#43; 1
if left >&#61; len(arr)
return

right :&#61; 2 * parent &#43; 2
minIndex :&#61; parent
minValue :&#61; arr[minIndex]
if arr[left] < minValue
minValue &#61; arr[left]
minIndex &#61; left

if right < len(arr)
if arr[right] < minValue
minValue &#61; arr[right]
minIndex &#61; right


if minIndex !&#61; parent
arr[minIndex], arr[parent] &#61; arr[parent], arr[minIndex]
// 递归&#xff0c;每当有元素调整下来时&#xff0c;要对以它为父节点的三角形区域进行调整
AdjustTraingle(arr, minIndex)


func ReverseAdjust(arr []int)
n :&#61; len(arr)
if n <&#61; 1
return

lastIndex :&#61; n / 2 * 2
fmt.Println(lastIndex)
// 逆序检查每一个三角形区域
for i :&#61; lastIndex; i > 0; i -&#61; 2
right :&#61; i
parent :&#61; (right - 1) / 2
fmt.Println(parent)
AdjustTraingle(arr, parent)


func buildHeap()
arr :&#61; []int62, 40, 20, 30, 15, 10, 49
ReverseAdjust(arr)
fmt.Println(arr)

每当有元素调整下来时&#xff0c;要对以它为父节点的三角形区域进行调整

插入元素

删除堆顶

下面讲几个堆的应用
堆排序&#xff1a;


  • 构建堆O(N)
  • 不断地删除堆顶O(NlogN)

求集合中最大的K个元素&#xff1a;


  • 用集合的前K个元素构建小根堆
  • 逐一遍历集合的其他元素&#xff0c;如果比堆顶小直接丢弃&#xff1b;否则替换掉堆顶&#xff0c;然后向下调整堆

把超时的元素从缓存中删除&#xff1a;


  • 按key的到期时间把key插入小根堆中
  • 周期扫描堆顶元素&#xff0c;如果它的到期时间早于当前时刻&#xff0c;则从堆和缓存中删除&#xff0c;然后向下调整堆

Golang中的container/heap实现了小根堆&#xff0c;但需要自己定义一个类&#xff0c;实现以下接口&#xff1a;


  • Len() int
  • Less(i, j int) bool
  • Swap(i, j int)
  • Push(x interface)
  • Pop() x interface

type Item struct
Value string
priority int // 优先级&#xff0c;数字越大&#xff0c;优先级越高

type PriorityQueue []*Item
func (pq PriorityQueue) Len() int
return len(pq)

func (pq PriorityQueue) Less(i, j int) bool
// Golang默认提供的是小根堆&#xff0c;而优先队列是大根堆&#xff0c;所以这里要反着定义Less
return pq[i].priority > pq[j].priority

func (pq PriorityQueue) Swap(i, j int)
pq[i], pq[j] &#61; pq[j], pq[i]

// 往slice里append&#xff0c;需要传slice指针
func (pq *PriorityQueue) Push(x interface)
item :&#61; x.(*Item)
*pq &#61; append(*pq, item)

// 让slice指向新的子切片&#xff0c;需要传slice指针
func (pq *PriorityQueue) Pop() interface
old :&#61; *pq
n :&#61; len(old)
item :&#61; old[n-1] // 数组最后一个元素
*pq &#61; old[0 : n-1] // 去掉最一个元素
return item


4. Trie树

Trie树又叫字典权
现有term集合&#xff1a;分散&#xff0c;分散精力&#xff0c;分散投资&#xff0c;分布式&#xff0c;工程&#xff0c;工程师&#xff0c;把它们放到Trie树里如下图&#xff1a;

Trie树的根节点是总入口&#xff0c;不存储字符&#xff1b;对于英文&#xff0c;第个节点有26个子节点&#xff0c;子节点可以存到数组里&#xff1b;中文由于汉字很多&#xff0c;用数组存子节点太浪费内存&#xff0c;可以用map存子节点&#xff1b;从根节点到叶节点的完整路径是一个term&#xff0c;从根节点到某个中间节点也可能是一个term&#xff0c;即一个term可能是另一个term的前缀&#xff1b;上图中红圈表示从根节点到本节点是一个完整的term

package main
import "fmt"
type TrieNode struct
Word rune // 当前节点存储的字符。byte只能表示英文字符&#xff0c;rune可以表示任意字符
Children map[rune]*TrieNode // 孩子节点&#xff0c;用一个map存储
Term string

type TrieTree struct
root *TrieNode

// add 把words[beginIndex:]插入到Trie树中
func (node *TrieNode) add(words []rune, term string, beginIndex int)
// words已经遍历完了
if beginIndex >&#61; len(words)
node.Term &#61; term
return

if node.Children &#61;&#61; nil
node.Children &#61; make(map[rune]*TrieNode)

word :&#61; words[beginIndex] // 把这个word放到node的子节点中
if child, exists :&#61; node.Children[word]; !exists
newNode :&#61; &TrieNodeWord: word
node.Children[word] &#61; newNode
newNode.add(words, term, beginIndex&#43;1) // 递归
else
child. var cpro_id = "u6885494";

推荐阅读
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了游标的使用方法,并以一个水果供应商数据库为例进行了说明。首先创建了一个名为fruits的表,包含了水果的id、供应商id、名称和价格等字段。然后使用游标查询了水果的名称和价格,并将结果输出。最后对游标进行了关闭操作。通过本文可以了解到游标在数据库操作中的应用。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
author-avatar
烟轻舞
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有